//=====================================================================
//    COPYRIGHT(C) Innobeam
//    ALL RIGHTS RESERVED
//=====================================================================
//Filename    : LCD_Update.v
//Created On  : 2019-12-10
//Author      : haoyu.xiao
//Description : LCD Data update
//Include     : 
//Modification: 
//=====================================================================
`timescale	1ns/100ps
`include	"../rtl/def_command.v"
module LCD_UPDATA(
	iClk,
	iRst_n,
	
	ovLCD_SPI_TxData,
	oLCD_SPI_Start,
	oLCD_DC,
	ivLCD_SPI_RxData,
	iLCD_SPI_Done,
	
	ivDisplay_state,
	iMoveStop,
	
	ovColumn,
	ovRow,
	ivFontcolor,
	ivBGcolor,
	ivAscii,
	
	iLCD_Start_Update,
	oLCD_Update_Done
	);
	
//========================================================================
//    parameter
//========================================================================
//parameter		BGColor = 16'hFFFF;
//parameter		FontColor = 16'H0000;
parameter		LCD_PAGE_ADDR = `LCD_PAGE_ADDR;
parameter		LCD_COLUMN_ADDR = `LCD_COLUMN_ADDR;
parameter		LCD_PAGE_ADDR_START = `LCD_PAGE_ADDR_START;
parameter		LCD_PAGE_ADDR_END = `LCD_PAGE_ADDR_END;
parameter		LCD_COLUMN_ADDR_START = `LCD_COLUMN_ADDR_START;
parameter		LCD_COLUMN_ADDR_END = `LCD_COLUMN_ADDR_END;
parameter		LCD_GRAM = `LCD_GRAM;
parameter		LCD_SLEEP_OUT = `LCD_SLEEP_OUT;
parameter		LCD_DISPLAY_ON = `LCD_DISPLAY_ON;
//========================================================================
//    port
//========================================================================	
	input					iClk;
	input					iRst_n;
	
	output		[7:0]		ovLCD_SPI_TxData;
	output					oLCD_SPI_Start;
	output					oLCD_DC;
	input		[7:0]		ivLCD_SPI_RxData;
	input					iLCD_SPI_Done;
	
	input		[4:0]		ivDisplay_state;
	input					iMoveStop;
	
	output		[4:0]		ovColumn;
	output		[4:0]		ovRow;
	input		[15:0]		ivFontcolor;
	input		[15:0]		ivBGcolor;
	input		[7:0]		ivAscii;
	
	input					iLCD_Start_Update;
	output					oLCD_Update_Done;
//========================================================================
//    signal
//========================================================================
	reg			[7:0]		rvByteData;
	wire		[7:0]		wvByteData;
	reg						rEPD_Start_Line;
	wire					wEPD_Line_Done;
	wire		[6:0]		wvCharNum;
	wire		[1:0]		wvEPD_Stage;
	reg						rFontCntEn;

	reg						rLCD_SPI_Start;
	reg						rLCD_DC;
	reg			[7:0]		rvLCD_SPI_TxData;
	reg						rLCD_Update_Done;
	reg			[7:0]		rvState;
	reg			[31:0]		rvByteCnt;
	reg			[9:0]		rvFontCnt;
	reg			[15:0]		rvpageaddrstart;
	reg			[15:0]		rvpageaddrend;
	reg			[15:0]		rvcolumaddrstart;
	reg			[15:0]		rvcolumaddrend;
		
	
//	reg		[6:0]		rvAscii;
	wire		[911:0]		wvCharBit_912;
	wire		[683:0]		wvCharBit_684;
	reg 		[7:0]		rvCharData;
	
	reg			[15:0]		BGColor;
	reg			[15:0]		FontColor;
	
	reg			[9:0]		rvColumn;
	reg			[4:0]		rvPage;
//========================================================================		
	assign 					ovLCD_SPI_TxData = rvLCD_SPI_TxData;
	assign 					oLCD_DC	= rLCD_DC;
	assign 					oLCD_SPI_Start = rLCD_SPI_Start;
	assign 					oLCD_Update_Done = rLCD_Update_Done;										  
//========================================================================		
Font16_LUT_UI	Font16_LUT_inst(
	.ivAscii			(ivAscii),//ivAscii
	.ovCharBit			(wvCharBit_684)	
	);

//Font16_LUT_R90 Font16_LUT_R90_inst (
//	.ivCharBit			(wvCharBitR90),
//	.ovCharBit			(wvCharBit)	
//	);
	
// Wait1s Wait1s_inst(		//wait 1000ms
	// .iClk				(iClk),
	// .iRst_n				(iRst_n),
	
	// .iWait5msStart		(rEPD_Update_Done),
	// .oWait5msDone		(oEPD_Update_Done)
	// );

//========================================================================	
	always@(posedge iClk or negedge iRst_n)begin
		if(!iRst_n)begin
			BGColor <= 16'hFFFF;
			FontColor <= 16'h0000;
		end
		else begin
			case(ivDisplay_state)
				5'b01110:begin
					BGColor <= 16'hFFFF;
					FontColor <= 16'hFFFF;
					end
				5'b01111:begin
					BGColor <= 16'h0000;
					FontColor <= 16'h0000;
					end
				5'b10000:begin
					BGColor <= 16'hF800;
					FontColor <= 16'hF800;
					end
				5'b10001:begin
					BGColor <= 16'h07E0;
					FontColor <= 16'h07E0;
					end
				5'b10010:begin
					BGColor <= 16'h001F;
					FontColor <= 16'h001F;
					end
				default:begin
					BGColor <= ivBGcolor;
					FontColor <= ivFontcolor;	
					end
			endcase
			end
		end

	//FSM
	always@(posedge iClk or negedge iRst_n)begin
			if(!iRst_n)begin	
				rLCD_SPI_Start		<= 1'b0;
				rLCD_DC				<= 1'b0;
				rvLCD_SPI_TxData 	<= 8'h0;
				rLCD_Update_Done	<= 1'b0;
				rvByteCnt			<= 32'd0;
				rvState				<= 8'h0;
				rvFontCnt			<= 10'd0;
				rvpageaddrstart		<= LCD_PAGE_ADDR_START;
				rvpageaddrend       <= LCD_PAGE_ADDR_END;
				rvcolumaddrstart    <= LCD_COLUMN_ADDR_START;
				rvcolumaddrend      <= LCD_COLUMN_ADDR_END;
				end
			else begin
				case (rvState)
				//waiting for updata
					8'd0: begin			
						rLCD_SPI_Start		<= 1'b0;
						rLCD_DC				<= 1'b0;
						rvLCD_SPI_TxData 	<= 8'h0;					
						rLCD_Update_Done 	<= 1'b0;
						rvpageaddrstart		<= LCD_PAGE_ADDR_START;
						rvpageaddrend       <= LCD_PAGE_ADDR_END;
						rvcolumaddrstart    <= LCD_COLUMN_ADDR_START;
						rvcolumaddrend      <= LCD_COLUMN_ADDR_END;						
						if (iLCD_Start_Update) begin		
							rvState <= 8'h1;
							end
						end
					//LCD software reset and delay 20ms
					8'd1: begin	
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b0;
						rvLCD_SPI_TxData <= LCD_SLEEP_OUT;
						rLCD_Update_Done <= 1'b0;
						rvState	<= rvState + 1'd1;						
						end	
					 8'd3: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b0;
						rvLCD_SPI_TxData <= LCD_DISPLAY_ON;		
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end	
						
					//Set Page address register 
					8'd5: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b0;
						rvLCD_SPI_TxData <= LCD_PAGE_ADDR;
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end	
					8'd7: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvpageaddrstart[15:8];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;						
						end	
					8'd9: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvpageaddrstart[7:0];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end	
					8'd11: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvpageaddrend[15:8];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;						
						end
					8'd13: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvpageaddrend[7:0];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end	
					8'd15: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b0;
						rvLCD_SPI_TxData <= LCD_COLUMN_ADDR;
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end	
					8'd17: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvcolumaddrstart[15:8];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;						
						end	
					8'd19: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvcolumaddrstart[7:0];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end	
					8'd21: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvcolumaddrend[15:8];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;						
						end
					8'd23: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rvLCD_SPI_TxData <= rvcolumaddrend[7:0];
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end	
					8'd25: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b0;
						rvLCD_SPI_TxData <= LCD_GRAM;
						rLCD_Update_Done <= 1'b0;	
						rvState	<= rvState + 1'd1;				
						end		
						
					8'd27: begin
						rLCD_SPI_Start <= 1'b1;
						rLCD_DC	<= 1'b1;
						rLCD_Update_Done <= 1'b0;	

						if(iLCD_SPI_Done == 1'b1 && rvByteCnt == 32'd1367)begin//rvByteCnt == 32'd1823
							if(rvFontCnt == 10'd103)
								rvState	<= rvState + 1'd1;
							else
								rvState <= 8'd5;
							
							if(rFontCntEn == 1'b1)begin
								rvpageaddrstart <= rvpageaddrstart - 8'd38;
								rvpageaddrend <= rvpageaddrend - 8'd38;
								rvcolumaddrstart <= LCD_COLUMN_ADDR_START;
								rvcolumaddrend <= LCD_COLUMN_ADDR_END;
								end
							else begin
								rvpageaddrstart <= rvpageaddrstart;
								rvpageaddrend <= rvpageaddrend;						
								rvcolumaddrstart <= rvcolumaddrstart - 8'd18;
								rvcolumaddrend <= rvcolumaddrend - 8'd18;
								end
							rvByteCnt <= 32'd0;	
							rvFontCnt <= rvFontCnt+ 1'b1;

							end
						else if(iLCD_SPI_Done == 1'b1)begin
							rvState <= rvState;
							rvByteCnt <= rvByteCnt +32'd1;
							rvFontCnt <= rvFontCnt;
							rvpageaddrstart <= rvpageaddrstart;
							rvpageaddrend <= rvpageaddrend;
							rvcolumaddrstart <= rvcolumaddrstart;
							rvcolumaddrend <= rvcolumaddrend;
							end
						else begin
							rvState <= rvState;
							rvByteCnt <= rvByteCnt;
							rvFontCnt <= rvFontCnt;
							rvpageaddrstart <= rvpageaddrstart;
							rvpageaddrend <= rvpageaddrend;
							rvcolumaddrstart <= rvcolumaddrstart;
							rvcolumaddrend <= rvcolumaddrend;
						end

					if(rvByteCnt[0] == 1'b0)begin
						if(wvCharBit_684[rvByteCnt[12:1]] == 1'b0)
							rvLCD_SPI_TxData <= FontColor[15:8];
						else
							rvLCD_SPI_TxData <= BGColor[15:8];
						end
					else begin
						if(wvCharBit_684[rvByteCnt[12:1]] == 1'b0)
							rvLCD_SPI_TxData <= FontColor[7:0];
						else
							rvLCD_SPI_TxData <= BGColor[7:0];
						end	
				
					if(rvFontCnt == 10'd12 || rvFontCnt == 10'd25 || rvFontCnt == 10'd38 || rvFontCnt == 10'd51 || rvFontCnt == 10'd64
						||rvFontCnt == 10'd77 || rvFontCnt == 10'd90 || rvFontCnt == 10'd103 )//
							rFontCntEn <= 1'b1;
					else
							rFontCntEn <= 1'b0;	
					end
					//wait 1 more clk to let spi master pull Done signal down.
					8'd2,8'd4,8'd6,8'd8,8'd10,8'd12,8'd14,8'd16,8'd18,8'd20,8'd22,8'd24,8'd26: begin
						rLCD_SPI_Start <= 1'b0;
						rLCD_DC	<= rLCD_DC;
						rvLCD_SPI_TxData <= rvLCD_SPI_TxData;
						rLCD_Update_Done <= 1'b0;
						if(iLCD_SPI_Done == 1'b1)begin
							rvState	<= rvState + 1'd1;
						end	
						end
					8'd28: begin
						rLCD_SPI_Start <= 1'b0;
						rLCD_DC	<= rLCD_DC;
						rvLCD_SPI_TxData <= rvLCD_SPI_TxData;				
						rvState	<= 8'h0;
						rLCD_Update_Done <= 1'b1;	
						rvFontCnt	<= 10'd0;	 				
						end	
					default:begin
						rLCD_SPI_Start <= 1'b0;
						rLCD_DC	<= 1'b0;
						rvLCD_SPI_TxData <= 8'h0;
						rLCD_Update_Done <= 1'b0;	
						rvState	<= 8'h0;		
						end
					endcase	
				end
		end
						
	always@(*) begin
		case(rvFontCnt)
			10'd0,10'd1,10'd2,10'd3,10'd4,10'd5,10'd6,10'd7,10'd8,10'd9,10'd10,10'd11,10'd12: begin
				rvPage			= 5'h0;
				rvColumn		= rvFontCnt;
				end
			10'd13,10'd14,10'd15,10'd16,10'd17,10'd18,10'd19,10'd20,10'd21,10'd22,10'd23,10'd24,10'd25: begin
				rvPage			= 5'h1;
				rvColumn		= rvFontCnt - 10'd13;
				end
			10'd26,10'd27,10'd28,10'd29,10'd30,10'd31,10'd32,10'd33,10'd34,10'd35,10'd36,10'd37,10'd38: begin
				rvPage			= 5'h2;
				rvColumn		= rvFontCnt - 10'd26;
				end
			10'd39,10'd40,10'd41,10'd42,10'd43,10'd44,10'd45,10'd46,10'd47,10'd48,10'd49,10'd50,10'd51: begin
				rvPage			= 5'h3;
				rvColumn		= rvFontCnt - 10'd39;
				end
			10'd52,10'd53,10'd54,10'd55,10'd56,10'd57,10'd58,10'd59,10'd60,10'd61,10'd62,10'd63,10'd64: begin
				rvPage			= 5'h4;
				rvColumn		= rvFontCnt - 10'd52;
				end
			10'd65,10'd66,10'd67,10'd68,10'd69,10'd70,10'd71,10'd72,10'd73,10'd74,10'd75,10'd76,10'd77: begin
				rvPage			= 5'h5;
				rvColumn		= rvFontCnt - 10'd65;
				end
			10'd78,10'd79,10'd80,10'd81,10'd82,10'd83,10'd84,10'd85,10'd86,10'd87,10'd88,10'd89,10'd90: begin
				rvPage			= 5'h6;
				rvColumn		= rvFontCnt - 10'd78;
				end
			10'd91,10'd92,10'd93,10'd94,10'd95,10'd96,10'd97,10'd98,10'd99,10'd100,10'd101,10'd102,10'd103: begin
				rvPage			= 5'h7;
				rvColumn		= rvFontCnt - 10'd91;
				end
			default: begin
				rvPage			= 5'h7;
				rvColumn		= 5'h0;
				end
			endcase
	end					
												
										
	assign ovColumn = rvColumn[4:0];
	assign ovRow = 	 rvPage;
endmodule